/*
 * Group.h
 *
 *  Created on: 11.03.2012
 *      Author: ignacio
 */

#ifndef GROUP_H_
#define GROUP_H_

#include "Character.h"
#include "SmartPointer.h"
#include "MovementBehaviour.h"
#include "Gluon.h"

namespace neurignacio{
/*
 * *******
 * House *
 * *******
 */
template <typename Type>
class House : public vector<SmartPointer<Type> >
{

public:
	House() : vector<SmartPointer<Type> >() {}
	void push_back(Type item);
	void push_back(SmartPointer<Type>  itemPtr) {if (itemPtr) vector<Type>::push_back(itemPtr);}
	Type& operator[](int index) {return *vector<SmartPointer<Type> >::operator[](index);}

};

template <typename Type>
void House<Type>::push_back(Type item)
{
	SmartPointer<Type> smartPointer(new Type(item));
	vector<SmartPointer<Type> >::push_back(smartPointer);
}
/*
 ****************************
 * ParentSteeringProperties *
 ****************************
 */
template <typename Type>
class ParentSteeringProperties
{
public:
	Type* parent;
	MovementBehaviourPointerContainer* parentMovementBehaviour; // Points to the parent'S movement behaviour
public:
	void getParentSteering() {parent->getSteering();}
	void parentRefresh() {parent->refresh();}
};
/*
 ******************************
 * ChildrenSteeringProperties *
 ******************************
 */
template <typename Type>
class ChildrenSteeringProperties
{
public:
	BasePointerContainer<Type>* children;
	void getChildrenSteering(SteeringOutput& initialSteering);
	void childrenRefresh();		// Refresh the position of the group members (children) to follow the steering of the Group as best they canv

};

template <typename Type>
void ChildrenSteeringProperties<Type>::getChildrenSteering(SteeringOutput& initialSteering)
{
	for (typename BasePointerContainer<Type>::iterator child=children->begin(); child!=children->end(); ++child)
	{
		(*child)->getSteering(initialSteering);
	}
}

template <typename Type>
void ChildrenSteeringProperties<Type>::childrenRefresh()
{
	for (typename BasePointerContainer<Type>::iterator child=children->begin(); child!=children->end(); ++child)
	{
		(*child)->refresh();
	}
}

/*
 ******************************
 * 			Parent 			  *
 ******************************
 */
template <typename ParentType, typename ChildrenType=ParentType>
class Parent : public ParentSteeringProperties<ParentType>, public ChildrenSteeringProperties<ChildrenType>
{
public:
	SteeringOutput& parentSteering;
public:
	Parent() : ParentSteeringProperties<ParentType>(), ChildrenSteeringProperties<ChildrenType>(), parentSteering(ParentSteeringProperties<ParentType>::parent->steering) {}
public:
	void getSteering(); // redefine getSteering => gets steering for Parent and Children
	void refresh();		// redefine refresh => refresh for Parent and Children
};

template <typename ParentType, typename ChildrenType>
void Parent<ParentType, ChildrenType >::getSteering()
{
	ParentSteeringProperties<ParentType>::getParentSteering();
	ChildrenSteeringProperties<ChildrenType>::getChildrenSteering(ParentSteeringProperties<ParentType>::parent->steering);
}

template <typename ParentType, typename ChildrenType>
void Parent<ParentType, ChildrenType >::refresh()
{
	ParentSteeringProperties<ParentType>::parentRefresh();
	ChildrenSteeringProperties<ChildrenType>::childrenRefresh();
}

typedef Parent<Gluon> GluonParent;
}


#endif /* GROUP_H_ */
